package com.boarsoft.rpc.generalize;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Parameter;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanWrapperImpl;

import com.boarsoft.common.util.BeanUtil;
import com.boarsoft.rpc.bean.RpcCall;
import com.boarsoft.rpc.bean.RpcMethodConfig;

public class RpcGenBroker {
	private static final Logger log = LoggerFactory.getLogger(RpcGenBroker.class);

	/**
	 * 服务端接收到请求时，将泛化的参数对象转换为实际参数对象
	 * 
	 * @param co
	 * @param mc
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public static void specialize(RpcCall co, RpcMethodConfig mc) throws Exception {
		Object[] args = co.getArguments();
		Parameter[] pa = mc.getParameters();
		for (int i = 0; i < args.length; i++) {
			Object so = args[i];
			if (so == null) {
				continue;
			}
			Class<?> pc = pa[i].getType();
			try {
				if (so instanceof RpcGenType) {
					args[i] = ((RpcGenType) so).specialize();
				} else if (so instanceof Map) {
					// 如果args[i]是Map，但实际参数不是Map，则尝试如下转换，反之不作处理
					if (!pc.isAssignableFrom(Map.class)) {
						// 这种只能针对目标对象属性的类型是可实例化的类而不是接口或抽象类的情况
						args[i] = pc.newInstance();
						BeanUtil.fillObjectWithMap(args[i], (Map<String, Object>) so);
					}
				} else if (so instanceof Set) {
				}
			} catch (Exception e) {
				log.error("Can not convert parameter {} to {}", args[i], pc, e);
				throw e;
			}
		}
	}

	/**
	 * 服务端返回结果时，将实际结果对象转换为泛化的对象
	 * 
	 * @param co
	 * @param ro
	 */
	@SuppressWarnings("unchecked")
	public static Object generalize(Object ro) {
		if (ro == null) {
			return null;
		}
		if (ro instanceof Class) {
			return null;
		}
		Class<?> clazz = ro.getClass();
		if (clazz.isPrimitive() || ro instanceof String || ro instanceof Byte || ro instanceof Short
				|| ro instanceof Integer || ro instanceof Long || ro instanceof Float || ro instanceof Double
				|| ro instanceof Boolean || ro instanceof BigDecimal) {
			return ro;
		}
		if (ro instanceof Map) {
			Map<Object, Object> sm = (Map<Object, Object>) ro;
			RpcGenMap tm = new RpcGenMap(sm.getClass().getName());
			for (Entry<Object, Object> en : sm.entrySet()) {
				tm.put(en.getKey(), RpcGenBroker.generalize(en.getValue()));
			}
			return tm;
		}
		if (ro instanceof Set) {
			Set<Object> ss = (Set<Object>) ro;
			RpcGenSet ts = new RpcGenSet();
			for (Object a : ss) {
				ts.add(RpcGenBroker.generalize(a));
			}
			return ts;
		}
		if (ro instanceof List) {
			List<Object> sl = (List<Object>) ro;
			RpcGenList tl = new RpcGenList();
			for (Object a : sl) {
				tl.add(RpcGenBroker.generalize(a));
			}
			return tl;
		}
		if (clazz.isArray()) {
			Object[] sa = (Object[]) ro;
			Object[] ta = new Object[sa.length];
			for (int i = 0; i < sa.length; i++) {
				ta[i] = RpcGenBroker.generalize(sa[i]);
			}
			return ta;
		}
		// 如果以上都不是，则尝试JSON转换
		// String json = JsonUtil.toJSONString(ro);
		// Map<String, Object> map = JsonUtil.parseObject(json, Map.class);
		// 直接反射塞值
		BeanWrapperImpl bw = new BeanWrapperImpl(ro);
		PropertyDescriptor[] pds = bw.getPropertyDescriptors();
		Map<String, Object> map = new HashMap<>();
		for (int i = 0; i < pds.length; ++i) {
			if (pds[i].getReadMethod() != null) {
				String k = pds[i].getName();
				if ("class".equals(k)) {
					continue;
				}
				Object v = bw.getPropertyValue(k);
				Object o = RpcGenBroker.generalize(v);
				map.put(k, o);
			}
		}
		return new RpcGenObj(clazz.getName(), map);
	}

}
